/**
 * This file is a part of qloudgen-sec. 
 * You can redistribute qloudgen-sec and/or modify it under the terms of the Lesser GNU General Public License version 3. 
 * qloudgen-sec is distributed WITHOUT ANY WARRANTY. 
 *
 * See the Lesser GNU General Public License for more details at http://www.gnu.org/licenses/. 
 **/
package org.qloudgen.sec.cas.support.user.userregistry.mongo;

import java.util.List;
import java.util.Random;

import javax.validation.constraints.NotNull;

import org.qloudgen.sec.cas.support.user.services.User;
import org.qloudgen.sec.cas.support.user.userregistry.UserRegistryDao;

import org.jasig.cas.authentication.UsernamePasswordCredential;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import org.springframework.data.mongodb.core.MongoTemplate;
/**
 * Implementation of <code>MongoUserRegistryDao</code> that uses a MongoDb repository as the backend persistence mechanism.
 * The repository is configured by the Spring application context.
 * <p/>
 * <p>The class will automatically create a default collection to use with services. The name of the collection may be specified
 * through {@link #setCollectionName(String)}. It also presents the ability to drop an existing collection and start afresh
 * through the use of {@link #setDropCollection(boolean)}.</p>
 *
 * 
 */
@Repository
public final class MongoUserRegistryDao implements UserRegistryDao,InitializingBean {

	private static final Logger logger = LoggerFactory.getLogger(MongoUserRegistryDao.class);

	private static final String MONGODB_COLLECTION_NAME = User.class.getSimpleName();

	private String collectionName = MONGODB_COLLECTION_NAME;

	private boolean dropCollection = false;

	@Autowired
	@NotNull
	private final MongoOperations mongoTemplate = null;

	@Override
	public void afterPropertiesSet() throws Exception {
		if (this.dropCollection) {
			logger.debug("Dropping database collection: {}", this.collectionName);
			this.mongoTemplate.dropCollection(this.collectionName);
		}

		if (!this.mongoTemplate.collectionExists(this.collectionName)) {
			logger.debug("Creating database collection: {}", this.collectionName);
			this.mongoTemplate.createCollection(this.collectionName);
		}
		if (this.mongoTemplate.count(new Query(),this.collectionName) == 0){
		  User user =new User();
			user.setName("casuser");
			user.setPassword("admin");
			user.setIsManageUser(true);
			user.setId(""+Math.abs((new Random()).nextLong()));
			
			this.mongoTemplate.save(user, this.collectionName);
	  }
		logger.debug("Creating default user casuser: {}", this.mongoTemplate.count(new Query(),this.collectionName));
	}

	@Transactional(readOnly = false)
	public boolean delete(final User svc) {
		if (this.findUserById(svc.getId()) != null) {
			this.mongoTemplate.remove(svc, this.collectionName);
			logger.debug("Removed user: {}", svc);
			return true;
		}
		return false;
	}

	@Transactional(readOnly = true)
	public User findUserById(final String svcId) {
		return this.mongoTemplate.findOne(new Query(Criteria.where("id").is(svcId)), User.class, this.collectionName);
	}
  
  @Transactional(readOnly = true)
	public User findUserByName(final String name) {
		return this.mongoTemplate.findOne(new Query(Criteria.where("name").is(name)), User.class, this.collectionName);
	}
  
  @Transactional(readOnly = true)
	public User findUserBy(String username,String password) {
		Query query = new Query();
		
		query.addCriteria(Criteria.where("name").is(username));
		query.addCriteria(Criteria.where("password").is(password));
		
		return this.mongoTemplate.findOne(query, User.class, this.collectionName);
	}
  
	@Transactional(readOnly = true)
	public List<User> load() {
		return this.mongoTemplate.findAll(User.class, this.collectionName);
	}

	@Transactional(readOnly = false)
	public User save(final User svc) {
    if (svc.getId() == null)
       svc.setId(""+Math.abs((new Random()).nextLong()));
		this.mongoTemplate.save(svc, this.collectionName);
		logger.debug("Saved user: {}", svc);
		return this.findUserById(svc.getId());
	}

	/**
	 * Optionally, specify the name of the mongodb collection where services are to be kept.
	 * By default, the name of the collection is specified by the constant {@link #MONGODB_COLLECTION_NAME}
	 */
	public void setCollectionName(final String name) {
		this.collectionName = name;
	}

	/**
	 * When set to true, the collection will be dropped first before proceeding with other operations.
	 */
	public void setDropCollection(final boolean dropCollection) {
		this.dropCollection = dropCollection;
	}
}
